package edu.udo.sopra10.chaturaji.entities.pieces;

import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableCollection;

import java.util.Collection;

import edu.udo.sopra10.chaturaji.entities.Player;
import edu.udo.sopra10.chaturaji.entities.Square;
import edu.udo.sopra10.chaturaji.entities.coordinates.Movement;
import edu.udo.sopra10.chaturaji.entities.coordinates.Position;
import edu.udo.sopra10.chaturaji.util.CloneUtil;

/**
 * A boat is one of the Chaturaji {@link Piece}s. It is worth two points.
 * Players start with a single boat in the leftmost square of their second row.
 * Boats move exactly two squares along any diagonal, jumping over pieces and
 * capturing opposing pieces they land on. Should a boat be moved in a way that
 * all player's boats are contained in a square afterwards, the boat triumph is
 * triggered and all opposing player's boats are captured.
 * 
 * @author Simon Dierl
 */
public final class Boat extends JumpingPiece {
	/**
	 * All movements a boat is theoretically capable of performing.
	 */
	private static final Collection<Movement> MOVEMENTS = unmodifiableCollection(asList(
			new Movement((byte) -2, (byte) -2), new Movement((byte) -2,
					(byte) 2), new Movement((byte) 2, (byte) -2),
			new Movement((byte) 2, (byte) 2)));

	/**
	 * Create a new {@link Boat}.
	 * 
	 * @param owner
	 *            the player owning the boat, must not be {@code null}.
	 * @param square
	 *            the square the boat stands on, may be {@code null} to indicate
	 *            a captured piece.
	 */
	public Boat(final Player owner, final Square square) {
		super(MOVEMENTS, (byte) 2, owner, square);
		this.pieceValue = 10;
	}

	@Override
	public Actions getPossibleActions(final Square[][] board,
			final Position currentPosition) {
		final Actions actions = super
				.getPossibleActions(board, currentPosition);
		for (final Position position : actions.getPossibleMoves()) {
			if (isBoatTriumphPosition(board, position)) {
				return new Actions(actions.getPossibleMoves(),
						actions.getPossibleCaptures(), position,
						actions.getPossiblePawnPromotions());
			}
		}
		for (final Position position : actions.getPossibleCaptures()) {
			if (isBoatTriumphPosition(board, position)) {
				return new Actions(actions.getPossibleMoves(),
						actions.getPossibleCaptures(), position,
						actions.getPossiblePawnPromotions());
			}
		}
		return actions;
	}

	/**
	 * Checks if a specific move triggers a boat triumph.
	 * 
	 * @param board
	 *            the game board to use.
	 * @param position
	 *            the position to check.
	 * @return {@code true} if a move to this position triggers a boat triumph.
	 */
	private boolean isBoatTriumphPosition(final Square[][] board,
			final Position position) {
		Position testPosition = CloneUtil.clone(position);
		byte xShift = 0;
		byte yShift = 0;

		// test x-axis for boats
		try {
			testPosition.shiftX((byte) -1);
			Piece piece = board[testPosition.getX()][testPosition.getY()]
					.getPiece();
			if ((piece != null) && (piece instanceof Boat)
					&& !(piece.equals(this))) {
				xShift = (byte) -1; // boat above
			} else {
				testPosition = CloneUtil.clone(position);
				try {
					testPosition.shiftX((byte) 1);
					piece = board[testPosition.getX()][testPosition.getY()]
							.getPiece();
					if ((piece != null) && (piece instanceof Boat)
							&& !(piece.equals(this))) {
						xShift = (byte) 1; // no boat above, boat below
					} else {
						return false; // no boats above or below
					}
				} catch (final IllegalArgumentException e) {
					return false; // no boat above, no board below
				}
			}
		} catch (final IllegalArgumentException e) {
			testPosition = CloneUtil.clone(position);
			testPosition.shiftX((byte) 1);
			final Piece piece = board[testPosition.getX()][testPosition.getY()]
					.getPiece();
			if ((piece != null) && (piece instanceof Boat)
					&& !(piece.equals(this))) {
				xShift = (byte) 1; // no board above, boat below
			} else {
				return false; // no board above, no boat below
			}
		}

		testPosition = CloneUtil.clone(position);

		// test y-axis for boats
		try {
			testPosition.shiftY((byte) -1);
			Piece piece = board[testPosition.getX()][testPosition.getY()]
					.getPiece();
			if ((piece != null) && (piece instanceof Boat)
					&& !(piece.equals(this))) {
				yShift = (byte) -1; // boat left
			} else {
				try {
					testPosition = CloneUtil.clone(position);
					testPosition.shiftY((byte) 1);
					piece = board[testPosition.getX()][testPosition.getY()]
							.getPiece();
					if ((piece != null) && (piece instanceof Boat)
							&& !(piece.equals(this))) {
						yShift = (byte) 1; // no boat left, boat right
					} else {
						return false; // no boats left or right
					}
				} catch (final IllegalArgumentException e) {
					return false; // no boat left, no board right
				}
			}
		} catch (final IllegalArgumentException e) {
			testPosition = CloneUtil.clone(position);
			testPosition.shiftY((byte) 1);
			final Piece piece = board[testPosition.getX()][testPosition.getY()]
					.getPiece();
			if ((piece != null) && (piece instanceof Boat)
					&& !(piece.equals(this))) {
				yShift = (byte) 1; // no board left, boat right
			} else {
				return false; // no board left, no boat right
			}
		}

		testPosition = CloneUtil.clone(position);

		// test computed corner for boat
		testPosition.shiftXY(xShift, yShift);
		final Piece piece = board[testPosition.getX()][testPosition.getY()]
				.getPiece();
		if ((piece != null) && (piece instanceof Boat) && !(piece.equals(this))) {
			return true; // boat in computed corner
		} else {
			return false; // no boat in computed corner
		}
	}
}
